﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Mail;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Caching;
using System.Web.Security;
using System.Xml;
using HtmlAgilityPack;
using MvcForum.Net.Business;
using MvcForum.Net.Business.Utils;
using MvcForum.Net.Configuration;
using MvcForum.Net.Enums;
using Nasa8x.Core;



namespace MvcForum.Net.Utils
{
    public static class ForumContext
    {



        public static HttpContext Context
        {
            get
            {

                return HttpContext.Current;
            }

        }


        #region UserInfo


        public static ForumConfiguration Configuration
        {
            get
            {
                return ForumConfiguration.Instance;
            }
        }

        public static UserInfo UserInfo
        {
            get
            {
                //if (Context.User.Identity.IsAuthenticated)
                //{
                    try
                    {

                        //User.Identity.Name
                        //var _cookie = Context.Request.Cookies.Get(FormsAuthentication.FormsCookieName);//FormsAuthentication.GetAuthCookie(FormsAuthentication.FormsCookieName, false);//

                       // 

                        var _u = (UserInfo)Context.Session["_USERINFO"];

                        if (_u == null)
                        {

                            var _cookie = Context.Request.Cookies.Get(FormsAuthentication.FormsCookieName);
                            string[] _userData = FormsAuthentication.Decrypt(_cookie.Value).UserData.Split(';');
                            _u = UsersRepository.LogIn(_userData[0], _userData[1], false);

                             //_u = UsersRepository.LogIn(Context.User.Identity.Name, "AUTO", false);
                            Context.Session["_USERINFO"] = _u;
                        }

                        return _u;

                    }
                    catch (Exception ex)
                    {

                        return null;
                    }



                //}
                //return null;
            }
        }

        #region SetAuthenticationCookie

        public static void SetAuthenticationCookie(string data, bool isPersit)
        {


            //FormsAuthentication.SetAuthCookie(data, isPersit);


            var _cookieDays = ForumConfiguration.Instance.CookieDays;

            var ticket =
                new FormsAuthenticationTicket(
                    1,
                    FormsAuthentication.FormsCookieName,
                    DateTime.UtcNow,
                    _cookieDays <= 0 ? DateTime.UtcNow.AddDays(1) : DateTime.UtcNow.AddDays(_cookieDays),
                    isPersit,
                    data,
                    FormsAuthentication.FormsCookiePath);

            /* Encrypt the ticket */
            string _encryptedTicket = FormsAuthentication.Encrypt(ticket);
            /* Create cookie */
            var _cookie = new HttpCookie(FormsAuthentication.FormsCookieName, _encryptedTicket);
            _cookie.HttpOnly = true;

            if (ticket.IsPersistent)
            {

                _cookie.Expires = ticket.Expiration;
            }


            /* Add cookie */
            Context.Response.Cookies.Add(_cookie);


            //FormsAuthentication.SetAuthCookie(username,isPersit);

            // Create ticket
            //FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
            //    1,
            //    "user",
            //    DateTime.Now,
            //    DateTime.Now.AddMinutes(3),
            //    true,
            //    "fabiano!",
            //    FormsAuthentication.FormsCookiePath);

            //// Create encrypted cookie
            //string hash = FormsAuthentication.Encrypt(ticket);
            //HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, hash);
            //if (ticket.IsPersistent)
            //{
            //    cookie.Expires = ticket.Expiration;
            //}

            //// Set and done
            //Response.Cookies.Add(cookie); //Necessary, otherwise UserData property gets lost





        }

        #endregion
        public static void SignOut()
        {
            FormsAuthentication.SignOut();

            HttpCookie cookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
            if (cookie != null)
            {
                cookie.Expires = DateTime.UtcNow.AddDays(-99);
                HttpContext.Current.Response.Cookies.Add(cookie);
            }


            //Context.Response.Cookies.Remove(FormsAuthentication.FormsCookieName);
            Context.Session.Clear();
            Context.Session.Abandon();
            Context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
            Context.Response.Cache.SetExpires(DateTime.Now.AddSeconds(-1));
            Context.Response.Cache.SetNoStore();
            Context.Response.AppendHeader("Pragma", "no-cache");



        }


        public static bool Logined
        {
            get
            {
                return UserInfo == null ? false : true;
            }
        }

        public static bool ForumAllowAccess(string allowRoles)
        {

            if (!string.IsNullOrEmpty(allowRoles))
            {

                if (Logined)
                {
                    string[] _roles = allowRoles.Split(',');

                    if (_roles.Any(role => role == UserInfo.RoleId.ToString()))
                    {
                        return true;
                    }

                }
                else
                {
                    return false;
                }


            }

            return true;

        }

        #endregion

        


        public static string Encrypt(params object[] _params)
        {

            var _sb = new StringBuilder(200);

            for (int i = 0; i < _params.Length; i++)
            {

                if (i > 0)
                    _sb.Append(",");
                _sb.Append(_params[i].ToString());
            }

            // More
            _sb.AppendFormat(",{0}", SessionID);

            return Encryptor.Encrypt(_sb.ToString(), Configuration.EncryptPassword);

        }


        public static string[] Decrypt(string _encryptString)
        {

            string _plainText = Encryptor.Decrypt(_encryptString, Configuration.EncryptPassword);
            return _plainText.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
        }


        #region Forum Url And Application Path

        public static string ApplicationFullPath
        {

            get
            {

                var _port = Context.Request.ServerVariables["SERVER_PORT"];

                if (String.IsNullOrEmpty(_port) || _port == "80" || _port == "443")
                {
                    _port = "";
                }
                else
                {
                    _port = ":" + _port;
                }


                String _protocol = Context.Request.ServerVariables["SERVER_PORT_SECURE"];

                if (String.IsNullOrEmpty(_protocol) || _protocol == "0")
                {
                    _protocol = "http://";
                }
                else
                {
                    _protocol = "https://";
                }


                if (Context.Request.ApplicationPath == "/")
                {

                    //App is installed in root
                    return _protocol + Context.Request.ServerVariables["SERVER_NAME"] + _port + "/";

                }
                //App is installed in virtual directory
                return _protocol + Context.Request.ServerVariables["SERVER_NAME"] + _port + Context.Request.ApplicationPath;
            }

        }



        //public  static string ApplicationPath
        //{
        //    get
        //    {
        //        string _applicationPath = "";
        //        //if (httpApplication.Request.Url != null)
        //        // Nick Farina: We need to cast to object first because the mono framework doesn't 
        //        // have the Uri.operator!=() method that the MS compiler adds. 
        //        if ((object)HttpContext.Current.Request.Url != null)
        //            _applicationPath = HttpContext.Current.Request.Url.AbsoluteUri.Substring(
        //                0, HttpContext.Current.Request.Url.AbsoluteUri.ToLower().IndexOf(
        //                HttpContext.Current.Request.ApplicationPath.ToLower(),
        //                HttpContext.Current.Request.Url.AbsoluteUri.ToLower().IndexOf(
        //                HttpContext.Current.Request.Url.Authority.ToLower()) +
        //                HttpContext.Current.Request.Url.Authority.Length) +
        //                HttpContext.Current.Request.ApplicationPath.Length);
        //        return _applicationPath;
        //    }
        //}


        public static string ApplicationPath
        {

            get
            {
                string _applicationPath = Context.Request.ApplicationPath;
                if (!_applicationPath.EndsWith("/")) _applicationPath += "/";

                //string _forumPath = ForumConfiguration.Instance.ApplicationUrl;
                //if (!string.IsNullOrEmpty(_forumPath) && _forumPath.StartsWith("/"))
                //    _forumPath = _forumPath.Remove(0, 1);

                //if (!string.IsNullOrEmpty(_forumPath) && !_forumPath.EndsWith("/")) _forumPath += "/";

                return _applicationPath;
            }

        }

        //return http://domain:port/forumPath/
        public static string ApplicationAbsoluteUrl
        {
            get
            {


                string _forumPath = ForumConfiguration.Instance.AbsoluteUrl;
                //if (!string.IsNullOrEmpty(_forumPath) && _forumPath.StartsWith("/"))
                //    _forumPath = _forumPath.Remove(0, 1);

                //if (!string.IsNullOrEmpty(_forumPath) && !_forumPath.EndsWith("/")) _forumPath += "/";

                return _forumPath;




            }
            //get
            //{
            //    string _applicationPath = "";
            //    //if (httpApplication.Request.Url != null)
            //    // Nick Farina: We need to cast to object first because the mono framework doesn't 
            //    // have the Uri.operator!=() method that the MS compiler adds. 
            //    if ((object)HttpContext.Current.Request.Url != null)
            //        _applicationPath = HttpContext.Current.Request.Url.AbsoluteUri.Substring(
            //            0, HttpContext.Current.Request.Url.AbsoluteUri.ToLower().IndexOf(
            //            HttpContext.Current.Request.ApplicationPath.ToLower(),
            //            HttpContext.Current.Request.Url.AbsoluteUri.ToLower().IndexOf(
            //            HttpContext.Current.Request.Url.Authority.ToLower()) +
            //            HttpContext.Current.Request.Url.Authority.Length) +
            //            HttpContext.Current.Request.ApplicationPath.Length);
            //    return _applicationPath;
            //}
        }


        public static string GetAbsoluteUrl(string _pageStringFormat, params object[] _params)
        {

            int _length = _params.Length + 2;
            var _args = new string[_length];
            _args[0] = ApplicationAbsoluteUrl;// first arg set Root Path

            for (int i = 0; i < _params.Length; i++)
            {
                _args[i + 1] = _params[i].ToString();
            }
            _args[_length - 1] = Configuration.Extension; // Last arg set extension


            return string.Format(_pageStringFormat, _args);
        }

        public static string GetAbsoluteUrl(string _pageStringFormat)
        {
            return string.Format(_pageStringFormat, ApplicationAbsoluteUrl, Configuration.Extension);
        }


        public static string ForumLink(ForumsListEntity _forum)
        {

            if (!string.IsNullOrEmpty(_forum.RemoteUrl))
            {

                return string.Format("<a class=\"fr-subject\" href=\"{0}\" title=\"{1}\">{1}</a>", _forum.RemoteUrl, Context.Server.HtmlEncode(_forum.ForumName));

            }
            return string.Format("<a class=\"fr-subject\" href=\"{0}\" title=\"{1}\">{1}</a>", ForumLink(_forum.ForumId, _forum.ForumName, null), Context.Server.HtmlEncode(_forum.ForumName));
        }

        public static string ForumLink(int _id, string _title, object _pageIndex)
        {
            //return ForumLink("forum", id, title, pageIndex);

            if (_pageIndex != null)
            {
                return string.Format(ForumUrls.FORUM_URL_PAGE, ApplicationAbsoluteUrl, _id, _pageIndex, Configuration.IsUrlPlainText ? ToPlainText(_title, true) : _title, Configuration.Extension);

            }
            return string.Format(ForumUrls.FORUM_URL, ApplicationAbsoluteUrl, _id, Configuration.IsUrlPlainText ? ToPlainText(_title, true) : _title, Configuration.Extension);

        }

        public static string ThreadLink(int _id, string _title, object _pageIndex)
        {
            string _link = _pageIndex != null ? string.Format(ForumUrls.THREAD_URL_PAGE, ApplicationAbsoluteUrl, _id, _pageIndex, Configuration.IsUrlPlainText ? ToPlainText(_title, true) : _title, Configuration.Extension) : string.Format(ForumUrls.THREAD_URL, ApplicationAbsoluteUrl, _id, Configuration.IsUrlPlainText ? ToPlainText(_title, true) : _title, Configuration.Extension);


            if (!string.IsNullOrEmpty(Context.Request.QueryString["highlight"]))
            {
                _link += "?highlight=" + Context.Server.UrlEncode(Context.Request.QueryString["highlight"]);

            }

            return _link;
        }


        #endregion

        #region Localizer

        private static Localizer _localizer;

        static Localizer Localizer
        {

            get
            {

                const string CACHE_KEY = "MF_LOCALIZER";

                object _o = CacheWaper.Get(CACHE_KEY);
                if (_o != null)
                {
                    _localizer = (Localizer)_o;
                }
                else
                {



                    string _filePath = Context.Server.MapPath(string.Format("{0}languages/{1}.xml", ApplicationPath, ForumConfiguration.Instance.DefaultLanguage));
                    _localizer = new Localizer(_filePath);

                    // If the file changes we want to reload it
                    var _dep = new CacheDependency(_filePath);

                    CacheWaper.Add(CACHE_KEY, _localizer, _dep);
                }
                return _localizer;

            }
        }


        public static string Empty
        {
            get { return "&nbsp;"; }
        }


        public static string GetText(string _page, string _entry)
        {

            return Localizer.GetValue(_page.ToUpper(), _entry.ToUpper());


        }

        public static string GetDate(string _entry)
        {

            return Localizer.GetDateValue(_entry.ToUpper());

        }

        public static string GetMessage(string _entry)
        {

            return Localizer.GetMessage(_entry.ToUpper());

        }


        public static string GetMessage(Messages _msg)
        {

            return GetMessage(_msg.ToString());


        }

        public static string GetGlobalText(string _entry)
        {

            return Localizer.GetGlobalValue(_entry.ToUpper());

        }

        #endregion

        #region Utils


        public static void MapBoolean(string expected, out bool value)
        {
            value = !string.IsNullOrEmpty(expected) && Regex.IsMatch(expected, "yes|y|on|true", RegexOptions.IgnoreCase);
        }

        public static string TruncateAtWord(this string input, int length)
        {
            if (input == null || input.Length < length)
                return input;
            input = input.Replace("&nbsp;", " ");
            int _iNextSpace = input.LastIndexOf(" ", length);
            return string.Format("{0}...", input.Substring(0, (_iNextSpace > 0) ? _iNextSpace : length).Trim());
        }


        public static string HtmlToPlainText(this string html)
        {
            var _doc = new HtmlDocument();
            _doc.LoadHtml(html);
            html = _doc.DocumentNode.InnerText;
            html = html.Replace("\r\n", " ").Replace("\n", " ").Replace("\t", string.Empty).Replace("\r", string.Empty);
            return html;
        }



        public static string Truncate(object input)
        {

            return Nasa8x.Core.Utils.Truncate(input, ForumConfiguration.Instance.TopicShowWordsLength);
        }


        /// <summary>
        /// Wraps matched strings in HTML span elements styled with a background-color
        /// </summary>
        /// <param name="text"></param>
        /// <param name="keywords">Comma-separated list of strings to be highlighted</param>
        /// <param name="cssClass">The Css color to apply</param>
        /// <param name="fullMatch">false for returning all matches, true for whole word matches only</param>
        /// <returns>string</returns>
        public static string HighlightKeyWords(this string text, string keywords, bool fullMatch)
        {
            if (text == String.Empty || keywords == String.Empty)
                return text;
            var words = keywords.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            if (!fullMatch)
                return words.Select(word => word.Trim()).Aggregate(text,
                             (current, pattern) =>
                             Regex.Replace(current,
                                             pattern,
                                               string.Format("<span class=\"highlight\">{0}</span>",
                                               "$0"),
                                               RegexOptions.IgnoreCase));
            return words.Select(word => "\\b" + word.Trim() + "\\b")
                        .Aggregate(text, (current, pattern) =>
                                  Regex.Replace(current,
                                  pattern,
                                    string.Format("<span class=\"highlight\">{0}</span>",
                                    "$0"),
                                    RegexOptions.IgnoreCase));

        }



        public static string HighlightKeywords(this string input, string keywords)
        {
            if (string.IsNullOrEmpty(input) || string.IsNullOrEmpty(keywords))
            {
                return input;
            }

            string[] _kws = keywords.Split(' ');
            foreach (string _k in _kws)
            {
                try
                {
                    input = Regex.Replace(input, _k, string.Format("<span class=\"highlight\">{0}</span>", "$0"), RegexOptions.IgnoreCase);
                }
                catch
                {
                    //
                }
            }
            return input;
        }


        public static string HighlightKeywords(this string input)
        {

            string _hl = Context.Request.QueryString["highlight"];

            return input.HighlightKeywords(_hl);



        }


        /// <summary>
        /// Finds web and email addresses in a string and surrounds then with the appropriate HTML anchor tags 
        /// </summary>
        /// <param name="s"></param>
        /// <returns>String</returns>
        public static string AutoParseLink(this string s)
        {
            //Finds URLs with no protocol
            var _urlregex = new Regex(@"\b\({0,1}(?<url>(www|ftp)\.[^ ,""\s<)]*)\b",
              RegexOptions.IgnoreCase | RegexOptions.Compiled);
            //Finds URLs with a protocol
            var _httpurlregex = new Regex(@"\b\({0,1}(?<url>[^>](http://www\.|http://|https://|ftp://)[^,""\s<)]*)\b",
              RegexOptions.IgnoreCase | RegexOptions.Compiled);
            //Finds email addresses
            var _emailregex = new Regex(@"\b(?<mail>[a-zA-Z_0-9.-]+\@[a-zA-Z_0-9.-]+\.\w+)\b",
              RegexOptions.IgnoreCase | RegexOptions.Compiled);
            s = _urlregex.Replace(s, " <a href=\"http://${url}\" rel=\"_blank\">${url}</a>");
            s = _httpurlregex.Replace(s, " <a href=\"${url}\" rel=\"_blank\">${url}</a>");
            s = _emailregex.Replace(s, "<a href=\"mailto:${mail}\">${mail}</a>");
            return s;
        }



        public static string BbCodeToHtml(this string html)
        {
            const RegexOptions _options = RegexOptions.Singleline | RegexOptions.IgnoreCase;


            var _regex = new Regex(@"\[quote=(.*?)\](.*)\[/quote\]", _options);

            while (_regex.IsMatch(html))
                html = _regex.Replace(html, "<div class=\"quote\"><div class=\"quote-head\">$1:</div><div class=\"quote-content\">$2</div></div>");

            // html = Regex.Replace(html, @"\[quote=(.*?)\](.*)\[/quote\]", "<div class=\"quote\"><div class=\"quote-poster\">$1:</div><div class=\"quote-content\">$2</div></div>", _options);

            _regex = new Regex(@"\[quote\](.*)\[/quote\]", _options);

            while (_regex.IsMatch(html))
            {
                html = _regex.Replace(html, "<div class=\"quote\"><div class=\"quote-content\">$1</div></div>");
            }


            // html = Regex.Replace(html, @"\[quote\](.*)\[/quote\]", "<div class=\"quote\"><div class=\"quote-content\">$1</div></div>", _options);



            _regex = new Regex(@"\[code=(.*?)\](.*)\[/code\]", _options);

            if (_regex.IsMatch(html))
                html = _regex.Replace(html, "<code name=\"code\" class=\"brush: {1}\">$2</code>");


            // YouTube
            _regex = new Regex(@"\[youtube\]http:\/\/([a-zA-Z]+.)youtube.com\/watch\?v=([a-zA-Z0-9_\-]+)\[\/youtube\]", _options);


            if (_regex.IsMatch(html))
            {
                html.Replace(html,
                             @"<object width=""425"" height=""344""><param name=""movie"" value=""http://www.youtube.com/v/$2""></param><param name=""allowFullScreen"" value=""true""></param><embed src=""http://www.youtube.com/v/$2"" type=""application/x-shockwave-flash"" allowfullscreen=""true"" width=""425"" height=""344""></embed></object>");
            }


            return html;

        }


        public static int TotalPage(int pageSize, int totalRows)
        {

            return (int)Math.Ceiling((double)totalRows / pageSize);

        }

        //public static string CheckImage(object _image)
        //{
        //    if (_image != null && _image.ToString().Length > 3)
        //        return _image.ToString();
        //    return ForumConfiguration.Instance.["NoImage"];

        //}

        public static String Padding(int i)
        {

            if (i <= 1) return string.Empty;
            string _out = "|";

            for (int j = 0; j < i; j++)
            {
                _out += "-";
            }
            return _out;
        }


        public static string ToPlainText(string input, bool convertForUrl)
        {

            return Nasa8x.Core.Utils.ToPlainText(input, convertForUrl);
        }

        public static string ToPlainText(string input)
        {
            return ToPlainText(input, false);
        }



        public static IEnumerator<string> MakeStringEnum(string[] arr)
        {
            return ((IEnumerable<string>)arr).GetEnumerator();
        }


        public static IEnumerable<ForumsListEntity> FindSub(List<ForumsListEntity> source, int parentId)
        {
            return source.Where(x => x.ParentId == parentId);
        }

        public static ForumsListEntity FindParent(List<ForumsListEntity> source, int forumId)
        {

            return source.FirstOrDefault(x => x.ForumId == forumId);


        }

        #endregion


        #region DateTime Format


        public static TimeSpan TimeZone
        {
            get
            {
                //float min = ForumConfiguration.Instance.TimeZoneOffset * 60;
                return TimeSpan.FromHours(ForumConfiguration.Instance.TimeZoneOffset);
                // return new TimeSpan(min / 60, min % 60, 0);
            }
        }

        /// <summary>
        /// Returns the user timezone offset from GMT
        /// </summary>
        public static TimeSpan TimeZoneOffsetUser
        {
            get
            {
                if (UserInfo != null)
                {


                    return TimeSpan.FromHours(UserInfo.TimeZone);
                    //return new TimeSpan(min / 60, min % 60, 0);


                }
                return TimeZone;
            }
        }


        public static string DateTimeFormat(DateTime _dateTime)
        {
            DateTime _dt = _dateTime + TimeZoneOffsetUser;

            return _dt.ToString(Configuration.DateTimeFormat);
        }

        public static string ShortDateTimeFormat(DateTime _dateTime)
        {
            DateTime _dt = _dateTime + TimeZoneOffsetUser;

            return _dt.ToString(GetDate("SHORT_DATE"));
        }

        public static string TimeFormat(DateTime _datetime)
        {

            _datetime += TimeZoneOffsetUser;
            try
            {
                return _datetime.ToString("hh:mm tt");
            }
            catch (Exception)
            {
                return _datetime.ToString("T");
            }
        }


        public static string PrettyDate(DateTime _date)
        {
            // 1.
            // Get time span elapsed since the date.
            TimeSpan _s = DateTime.UtcNow.Subtract(_date);

            // 2.
            // Get total number of days elapsed.
            var _dayDiff = (int)_s.TotalDays;

            // 3.
            // Get total number of seconds elapsed.
            var _secDiff = (int)_s.TotalSeconds;

            // 4.
            // Don't allow out of range values.
            if (_dayDiff < 0 || _dayDiff >= 31)
            {
                return DateTimeFormat(_date);
            }

            // 5.
            // Handle same-day times.
            if (_dayDiff == 0)
            {
                // A.
                // Less than one minute ago.
                if (_secDiff < 60)
                {
                    return string.Format(GetDate("JUST_NOW"), _secDiff == 0 ? 1 : _secDiff); //"just now";
                }
                // B.
                // Less than 2 minutes ago.
                if (_secDiff < 120)
                {
                    return string.Format(GetDate("MINUTES_AGO"), 1);// "1 minute ago";
                }
                // C.
                // Less than one hour ago.
                if (_secDiff < 3600)
                {
                    return string.Format(GetDate("MINUTES_AGO"),
                        Math.Floor((double)_secDiff / 60));
                }
                // D.
                // Less than 2 hours ago.
                if (_secDiff < 7200)
                {
                    return string.Format(GetDate("HOURS_AGO"), 1); ;
                }
                // E.
                // Less than one day ago.
                if (_secDiff < 86400)
                {
                    return string.Format(GetDate("HOURS_AGO"),
                        Math.Floor((double)_secDiff / 3600));
                }
            }
            // 6.
            // Handle previous days.
            if (_dayDiff == 1)
            {
                var _dt = _date + TimeZoneOffsetUser;
                return string.Format(GetDate("YESTERDAY_AT"), _dt);
            }
            if (_dayDiff < 7)
            {
                return string.Format(GetDate("DAYS_AGO"), _dayDiff);
            }
            return _dayDiff < 31 ? string.Format(GetDate("WEEKS_AGO"), Math.Ceiling((double)_dayDiff / 7)) : DateTimeFormat(_date);

            // Default full date format
        }



        #endregion



        #region Validate

        public static bool NameIsDisallowed(string name)
        {


            if (!String.IsNullOrEmpty(Configuration.DisallowedUserNames))
            {
                const string regExWildcard = @"[\w\W]*?"; //"[a-zA-Z0-9]*";
                const RegexOptions regExOpt = RegexOptions.IgnoreCase;
                string[] _Names = Configuration.DisallowedUserNames.Split(new char[] { ',', ';' });

                return _Names.Select(s => String.Format(@"^{0}$", s.Replace("*", regExWildcard))).Select(thePattern => new Regex(thePattern, regExOpt)).Any(regEx => regEx.IsMatch(name));
            }
            return false;
        }


        public static bool AllowEmail(string email)
        {

            if (string.IsNullOrEmpty(Configuration.AllowEmails) || "*".Equals(Configuration.AllowEmails))
            {
                return true;
            }
            else
            {
                const string regExWildcard = @"[_a-z0-9-]+(\.[_a-z0-9-]+)*";//@"[^\w\-\.]";//"[A-Z0-9._%+-]+";
                const RegexOptions regExOpt = RegexOptions.IgnoreCase;
                string[] _Names = Configuration.AllowEmails.Split(new char[] { ',', ';' });

                return _Names.Select(s => String.Format(@"^{0}$", s.Replace("*", regExWildcard))).Select(thePattern => new Regex(thePattern, regExOpt)).Any(regEx => regEx.IsMatch(email));

            }
        }


        #endregion



        #region NavMenu Render

        public static string NavMenuRender(out List<PageEntity> Pages)
        {
            var _sb = new StringBuilder(1200);

            var _pages = new List<PageEntity>();
            PageEntity _page;

            if (Localizer.XmlDocument.DocumentElement != null)
            {
                XmlNodeList _nodes = Localizer.XmlDocument.DocumentElement.SelectNodes("navmenu/entry");

                if (_nodes != null)
                {

                    // _sbNavMenu.Append("<ul id=\"nav-menu\">");

                    foreach (XmlNode _node in _nodes)
                    {

                        bool _allowShow;



                        if (UserInfo == null)
                        {

                            _allowShow = _node.Attributes["showLogined"] == null || !bool.Parse(_node.Attributes["showLogined"].Value);

                        }
                        else
                        {
                            _allowShow = _node.Attributes["showLogined"] == null || bool.Parse(_node.Attributes["showLogined"].Value);


                        }

                        if (_allowShow)
                        {
                            string _class = _node.Attributes["class"] != null ? string.Format(" class=\"{0}\"", _node.Attributes["class"].Value) : string.Empty;
                            string _link = _node.Attributes["link"].Value;


                            //if (!string.IsNullOrEmpty(_node.Attributes["text"].Value))
                            //    _JumpLinks.Add(_link, _node.Attributes["text"].Value);
                            string _absoluteLink = GetAbsoluteUrl(_link);
                            if (!string.IsNullOrEmpty(_link))
                            {

                                _page = new PageEntity();
                                _page.Url = _absoluteLink;
                                _page.Name = _node.InnerText;
                                _pages.Add(_page);
                            }

                            _sb.AppendFormat("<li{0}><a href=\"{1}\">{2}</a></li>", _class, _absoluteLink, _node.InnerText);

                            //_sbNavMenu.AppendFormat("<li{0}><a href=\"{1}\">{2}</a></li>", _class, _link, _node.Attributes["text"].Value);
                        }


                    }



                }
            }


            //if li menu item have style attr float:right --> Reverse
            // _NavMenuItems.Reverse();

            Pages = _pages;
            return string.Format("<ul id=\"navbar\">{0}</ul>", _sb);



        }
        #endregion


        #region Forum Icon Render

        public static string ForumIcon(ForumsListEntity _forum)
        {

            string _type = "not-new";
            if (_forum.IsLocked)
                _type = "locked";
            else if (!string.IsNullOrEmpty(_forum.RemoteUrl))
                _type = "link";
            else if (_forum.LastPostId > 0 && _forum.LastPostDate > (DateTime.UtcNow - TimeSpan.FromDays(ForumConfiguration.Instance.NewReplyDaysAgo)))

                _type = "new";



            return string.Format("<div class=\"{0}-icon {0}-{1}\">&nbsp;</div>", "forum", _type);

        }

        public static string TopicLink(TopicEntity _topic)
        {
            if (!string.IsNullOrEmpty(_topic.RemoteUrl) && _topic.RemoteUrl.StartsWith("http"))
            {
                return string.Format("<a class=\"fr-subject\" href=\"{0}\" title=\"{1}\">{1}</a>", _topic.RemoteUrl,
                                     Context.Server.HtmlEncode(_topic.TopicName));
            }
            else
            {

                return string.Format("<a class=\"fr-subject\" href=\"{0}\" title=\"{1}\">{1}</a>", ThreadLink(_topic.TopicId, _topic.TopicName, null),
                                     Context.Server.HtmlEncode(_topic.TopicName));

            }
        }

        public static string TopicIcon(TopicEntity _topic)
        {


            string _type = string.Empty;


            if (_topic.Priority > 0)
            {

                _type = (_topic.Priority == (int)PriorityType.Notice) ? "notice" : "sticky";


            }
            else
            {
                if (_topic.IsLocked)
                {
                    _type = "locked";

                }

                else if (!string.IsNullOrEmpty(_topic.RemoteUrl))
                {
                    _type = "link";
                }
                else if (_topic.PollID.HasValue && _topic.PollID.Value > 0)
                {
                    _type = "poll";
                }

                else if (_topic.MovedToForumId.HasValue && _topic.MovedToForumId.Value > 0)
                {
                    _type = "moved";
                    goto Finish;
                }
                else if (_topic.TotalReplies > ForumConfiguration.Instance.HotReplyThreshold && _topic.LastPosted > (DateTime.UtcNow - TimeSpan.FromDays(Configuration.NewReplyDaysAgo)))
                {
                    _type = "hot";
                }


                if ((_topic.LastPostId > 0 && _topic.LastPosted > (DateTime.UtcNow - TimeSpan.FromDays(Configuration.NewReplyDaysAgo)) || _topic.Created > (DateTime.UtcNow - TimeSpan.FromDays(Configuration.NewReplyDaysAgo))))
                {
                    _type += ((!string.IsNullOrEmpty(_type)) ? "-" : "") + "new";
                }
                else
                {
                    _type = "not-new";

                }


            }

        Finish:

            return string.Format("<div class=\"{0}-icon {0}-{1}\">&nbsp;</div>", "topic", _type);

        }


        #endregion



        public static int PageIndex
        {
            get
            {
                string _p = Context.Request.QueryString["p"];
                if (!string.IsNullOrEmpty(_p))
                    return int.Parse(_p);
                return 1;
            }
        }

        public static string SessionID
        {
            get
            {
                if (Context.Session["MF_VISITOR"] == null)
                {
                    Context.Session["MF_VISITOR"] = Guid.NewGuid().ToString().Replace("-", "");
                }
                return Context.Session["MF_VISITOR"].ToString();


            }
        }

        public static string ClientIp
        {
            get
            {
                string _ip = Context.Request.UserHostAddress;
                if (_ip == "::1" || string.IsNullOrEmpty(_ip)) _ip = "127.0.0.1";

                return _ip;
            }
        }

        public static void UserActivityUpdate(PageEntity _page, int _forumId, int _topicId)
        {

            string _platform = Context.Request.Browser.Platform;
            string _browser = Context.Request.Browser.Browser;
            string _version = Context.Request.Browser.Version;
            string _sessionId = SessionID;
            string _ip = ClientIp;


            //  string _url = Context.Request.RawUrl;


            if (Context.Request.UserAgent != null)
            {

                string _userAgent = Context.Request.UserAgent;

                //    if (_userAgent.IndexOf("Windows NT 5.2") >= 0)
                //        _platform = "Win2003";
                //    else if (_userAgent.IndexOf("Windows NT 6.0") >= 0)
                //        _platform = "Vista";
                //    else if (_userAgent.IndexOf("Windows NT 6.1") >= 0)
                //        _platform = "Windows 7";

                if (_userAgent.IndexOf("Chrome") > 0)
                {
                    _browser = "Chrome";
                    int _startPoint = _userAgent.IndexOf("Chrome/") + 7;
                    int _endPoint = _userAgent.IndexOf(" ", _startPoint) + 1;
                    _version = _userAgent.Substring(_startPoint, _endPoint - _startPoint);
                }

            }


            _browser += " " + _version;

            UsersRepository.UserActivityUpdate(_sessionId, Logined ? UserInfo.UserId : 0, Logined ? UserInfo.UserName : string.Empty, _ip, _page.Name, _page.Url, _forumId, _topicId, _browser, _platform, Configuration.PastMinutes);


            //  Context.Session.SessionID


        }


        #region PageRender

        public static string PageRender(string pageFormatString, int pageIndex, int pageSize, int totalRows)
        {

            var totalPage = (int)Math.Ceiling((double)totalRows / pageSize);

            if (totalPage <= 1) return string.Empty;

            const int pageButtonCount = 3;
            int min = pageIndex - pageButtonCount;
            int max = pageIndex + pageButtonCount;

            if (max > totalPage)
                min -= max - totalPage;
            else if (min < 1)
                max += 1 - min;

            var _sb = new StringBuilder(1000);
            bool needDiv = false;


            _sb.Append("<ul class=\"paging\">");


            _sb.Append("<li class=\"page-x-of-y\"><span>");
            _sb.AppendFormat(GetGlobalText("PAGE_X_OF_Y"), pageIndex, totalPage);
            _sb.Append("</span></li>");

            //Ren Prev Button
            if (pageIndex > 1)
            {
                _sb.AppendFormat(
               "<li class=\"{1}\" onclick=\"window.location='{0}'\"><a title=\"Go to First Page\" href=\"{0}\">&nbsp;&nbsp;</a></li>", string.Format(pageFormatString, 1), "page-first");


                _sb.AppendFormat("<li class=\"page-prev\" onclick=\"window.location='{0}'\"><a href=\"{0}\" title=\"Go to Previous Page\">&nbsp;&nbsp;</a></li>", string.Format(pageFormatString, pageIndex - 1));


            }



            for (int i = 1; i <= totalPage; i++)
            {
                if (i <= 2 || i > totalPage - 2 || (min <= i && i <= max))
                {

                    string _className = (i == pageIndex) ? "actived" : "page-item";

                    _sb.AppendFormat("<li onclick=\"window.location='{0}'\" class=\"{1}\"><a href=\"{0}\">{2}</a></li>", string.Format(pageFormatString, i), _className, i);
                    needDiv = true;
                }
                else if (needDiv)
                {
                    _sb.AppendFormat("<li class=\"{0}\">...</li>", "page-item");
                    needDiv = false;
                }
            }

            //Ren Next Button
            if (pageIndex < totalPage)
            {
                _sb.AppendFormat(
                    "<li class=\"{1}\" onclick=\"window.location='{0}'\"><a title=\"Go to Next Page\" href=\"{0}\">&nbsp;&nbsp;</a></li>", string.Format(pageFormatString, pageIndex + 1), "page-next");

                _sb.AppendFormat(
                  "<li class=\"{1}\" onclick=\"window.location='{0}'\"><a title=\"Go to Last Page\" href=\"{0}\">&nbsp;&nbsp;</a></li>", string.Format(pageFormatString, totalPage), "page-last");


            }


            _sb.Append("</ul>");

            return _sb.ToString();


        }

        #endregion

        //public static string PageRender(string pageFormatString, int pageIndex, int? pageSize, int totalRows)
        //{

        //    int totalPage = TotalPage(pageSize.HasValue ? pageSize.Value : Configuration.PageSize, totalRows);

        //    if (totalPage <= 1) return string.Empty;

        //    const int pageButtonCount = 3;
        //    int min = pageIndex - pageButtonCount;
        //    int max = pageIndex + pageButtonCount;

        //    if (max > totalPage)
        //        min -= max - totalPage;
        //    else if (min < 1)
        //        max += 1 - min;

        //    var _sb = new StringBuilder(1000);
        //    bool needDiv = false;

        //    _sb.AppendFormat("<div class=\"{0}\">", "page-container");
        //    _sb.AppendFormat("<table cellpadding=\"0\" cellspacing=\"1\" style=\"width:auto;\"><tr>");

        //    _sb.AppendFormat("<td class=\"{0}\">", "page-x-of-y");

        //    _sb.Append(string.Format("Page {0} of {1}", pageIndex, totalPage));

        //    _sb.Append("</td>");


        //    //Ren Prev Button
        //    if (pageIndex > 1)
        //        _sb.AppendFormat(
        //            "<td onclick=\"{0}\" class=\"{1}\"><a href=\"{0}\">«</a></td>",
        //            string.Format(pageFormatString, pageIndex - 1), "page-item");


        //    for (int i = 1; i <= totalPage; i++)
        //    {
        //        if (i <= 2 || i > totalPage - 2 || (min <= i && i <= max))
        //        {

        //            string _className = (i == pageIndex) ? "page-item-actived" : "page-item";

        //            _sb.AppendFormat("<td onclick=\"{0}\" class=\"{1}\"><a href=\"{0}\">{2}</a></td>", string.Format(pageFormatString, i), _className, i);
        //            needDiv = true;
        //        }
        //        else if (needDiv)
        //        {
        //            _sb.AppendFormat("<td class=\"{0}\">...</td>", "page-item");
        //            needDiv = false;
        //        }
        //    }

        //    //Ren Next Button
        //    if (pageIndex < totalPage)
        //        _sb.AppendFormat(
        //            "<td onclick=\"{0}\" class=\"{1}\"><a href=\"{0}\">&#187;</a></td>",
        //            string.Format(pageFormatString, pageIndex + 1), "page-item");

        //    _sb.Append("</tr></table>");
        //    _sb.Append("</div>");

        //    return _sb.ToString();
        //}


        #region Send Mail


        public static void SendMail(string from, string to, string subject, string body)
        {
            //var _sender = new SmtpSender(Configuration.SmtpServer);

            //_sender.Port = Configuration.SmtpPort;
            //_sender.EnableSsl = Configuration.SmtpSsl;

            //_sender.UserName = Configuration.SmtpUserName;
            //_sender.Password = Configuration.SmtpUserPass;

            //_sender.Send(from,to,subject,msg);


            var _mail = new MailMessage(new MailAddress(from, Configuration.ForumName), new MailAddress(to));

            _mail.Subject = string.Format("[{0}] - {1}", Configuration.ForumName, subject);
            _mail.Body = body + GetGlobalText("EMAIL_SIGNATURE");
            _mail.ReplyTo = new MailAddress(Configuration.SmtpReplyTo);
            _mail.BodyEncoding = Encoding.UTF8;
            //_mail.CC.Add();
            _mail.Bcc.Add(new MailAddress(Configuration.ForumEmail));
            _mail.IsBodyHtml = true;
            _mail.Priority = MailPriority.High;
            //SmtpClient smtpMail = new SmtpClient("smtp.gmail.com");
            var _smtpMail = new SmtpClient(Configuration.SmtpServer);
            _smtpMail.Port = Configuration.SmtpPort;
            _smtpMail.EnableSsl = Configuration.SmtpSsl;

            if (!string.IsNullOrEmpty(Configuration.SmtpUserName) && !string.IsNullOrEmpty(Configuration.SmtpUserPass))
            {

                _smtpMail.Credentials = new NetworkCredential(Configuration.SmtpUserName, Configuration.SmtpUserPass);
            }

            // and then send the mail
            _smtpMail.Send(_mail);


        }


        #endregion

        #region SanitizeHtml

        public static string HtmlSanitize(this string html, string[] allowHtmlTags, string[] allowHtmlAttributes)
        {

            var _doc = new HtmlDocument();
            _doc.OptionWriteEmptyNodes = true; //autoclose hr, br etc
            _doc.LoadHtml(html);

            string[] _elementWhitelist = allowHtmlTags;
            string[] _attributeWhiteList = allowHtmlAttributes;


            IList<HtmlNode> _hnc = _doc.DocumentNode.DescendantNodes().ToList();

            //remove non-white list nodes
            for (int i = _hnc.Count - 1; i >= 0; i--)
            {
                HtmlNode _htmlNode = _hnc[i];
                if (!_elementWhitelist.Contains(_htmlNode.Name.ToLower()))
                {
                    _htmlNode.Remove();
                    continue;
                }

                if (_htmlNode.Name.ToLower() == "pre")
                {
                    _htmlNode.InnerHtml = _htmlNode.InnerHtml.Replace("<br>", Environment.NewLine).Replace("<br />", Environment.NewLine);
                }

                for (int att = _htmlNode.Attributes.Count - 1; att >= 0; att--)
                {
                    HtmlAttribute _attribute = _htmlNode.Attributes[att];
                    string _attrName = _attribute.Name.ToLower();
                    //remove any attribute that is not in the white list (such as event handlers)
                    if (!_attributeWhiteList.Contains(_attrName))
                    {
                        _attribute.Remove();
                    }

                    //strip any "style" attributes that contain the word "expression"
                    if (_attrName == "style" && (_attribute.Value.ToLower().Contains("expression") || _attribute.Value.ToLower().Contains("position")))
                    {
                        _attribute.Value = string.Empty;

                        //_attribute.Value = Nasa8x.Core.Encoder.HtmlAttributeEncode(_attribute.Value);
                    }


                    if (_attrName == "src" || _attrName == "href")
                    {
                        //strip if the link starts with anything other than http (such as jscript, javascript, vbscript, mailto, ftp, etc...)
                        if (!_attribute.Value.StartsWith("http") && !_attribute.Value.StartsWith("/"))
                            _attribute.Value = "#";
                    }
                }
            }
            return _doc.DocumentNode.WriteTo();


        }

        public static string SanitizeHtml(this string html, string[] _allowHtmlTags)
        {


            string[] _attributeWhiteList = Configuration.HtmlWhiteAttributes.Split(new char[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries);


            return html.HtmlSanitize(_allowHtmlTags, _attributeWhiteList);
        }

        public static string HtmlSanitize(this string html)
        {

            //string[] _elementWhitelist = new string[]{ "a", "u", "b", "i", "br", "br ", "br", "h1", "h2", "h3", "h4", "h5", "h6", "span","pre","#text",
            //                                "div", "blockquote", "em", "sub", "sup", "s", "font", "ul", "li", "ol", "p","table","tr","td","tbody","th"

            //}; 

            string[] _elementWhitelist = Configuration.HtmlWhiteTags.Split(new char[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries);


            return html.SanitizeHtml(_elementWhitelist);


        }

        #endregion



        #region Logging


        private static String LoggingPath
        {
            get
            {
                // return HttpContext.Current.Server.MapPath();

                string _path = ConfigurationManager.AppSettings["LoggingPath"];

                if (!Directory.Exists(Context.Server.MapPath(_path)))
                {

                    Directory.CreateDirectory(Context.Server.MapPath(_path));
                }

                return Context.Server.MapPath(_path);
            }
        }




        public static void Log(String message)
        {

            string _fileLog = DateTime.Now.ToString("yyyyMMdd") + ".txt";

            using (StreamWriter w = File.AppendText(LoggingPath + _fileLog))
            {
                Log(message, w);
                // Close the writer and underlying file.
                w.Close();
            }

        }


        public static void Log(String logMessage, TextWriter w)
        {

            w.WriteLine("[{0}] : {1}", DateTime.Now.ToString("yyyyMMdd HH:mm:ss tt"), logMessage);
            w.WriteLine("-------------------------------");
            w.Flush();
        }


        #endregion

    }
}
